`timescale 1ns / 1ps
module Sync_port(
/**********NAND flash Sync mode Port*********/
//  output      CE_s,  
    output      CLK,  
    output      WR,     
    output      CLE,   
    output      ALE,   
    inout[7:0]  DQ,     
    inout       DQS,    
    input       RB,     
/***********Mode control port**************/
    input       clkX2,
    input       dclk,
    input       rst_n,
    input       en,         //port module enable
    input[2:0]  Cmd,  //
    input[7:0]  InputVal,       //
    output      IV_En,
    output[7:0] ReadVal,
    output      RV_En,
    input[31:0] RWDataNum,
    input[31:0] RWDataCounter
);

wire[7:0] I_DQ;
wire      I_DQS;
wire      clk_m;
wire      dqs_m;
wire      ready_r;
wire      dclk_m;
wire[7:0] O_DQ;

reg[7:0]  O_DQ_r0;
reg[7:0]  O_DQ_r1;
reg[7:0]  val_r;
reg      dv_r;
reg      CorD;
reg      dqs_en;
reg      clk_en;
reg      ale_r;
reg      cle_r;
reg      wr_r;
reg      dclk_en;
reg      clk_en;
reg      read_en;
reg      dqs_en;
reg      dataIn_rdy;
reg      ien;
wire     ien_w;

assign O_DQ = CorD ? O_DQ_r0 : O_DQ_r1;
assign IV_En = en ? ready_r : 1'bz;
assign ready_r = (Cmd === State_WriteData | Cmd === State_WriteWait) ? dataIn_rdy : ien_w;
assign ien_w = ien ? dclk_m : 1'b0;
assign clk_m = en & clkX2;
assign CLK = en ? (clk_en ? dclk_m : 1'b1) : 1'bz;
assign dclk_m = ~(dclk & dclk_en);
assign ALE = en ? ale_r : 1'bz;
assign CLE = en ? cle_r : 1'bz;
assign WR = en ? wr_r : 1'bz;
assign I_DQ = DQ;
assign DQ = read_en ? 8'hzz : O_DQ;
assign I_DQS = DQS;
assign DQS = read_en ? 1'hz : dqs_m;
assign dqs_m = dqs_en ? dclk_m : 1'b0;
assign ReadVal = en ? val_r : 8'hzz;
assign RV_En = en ? dv_r : 1'bz;

parameter tWRCK = 4'h04;
parameter Tdqss = 8'h04;


parameter State_command =   3'b000;
parameter State_adderss =   3'b001;
parameter State_WriteData = 3'b010;
parameter State_ReadData  = 3'b011;
parameter State_Idle =      3'b100;
parameter State_WriteWait = 3'b111;

reg[2:0] last_cmd;
always @(posedge clk_m or negedge rst_n) begin
    if (rst_n) begin// 
        if (Cmd === State_Idle & last_cmd === State_Idle | Cmd === State_ReadData) begin
            ien <= 1'b0;
        end else begin
            ien <= 1'b1;
        end
        last_cmd <= Cmd;
    end else begin
        ien <= 1'b0;
        last_cmd <= State_Idle;
    end
end

always @(posedge clk_m or negedge rst_n) begin
    if(rst_n != 1'b0) begin
        if (Cmd ===  State_ReadData) begin
            wr_r <=  1'b0;
        end else begin
            wr_r <=  1'b1;
        end
    end else begin
        wr_r <=     1'b1;
    end
end

reg[7:0] dclkCounter;
reg write_rst_n;

always @(posedge clk_m or negedge rst_n) begin
   if (rst_n) begin
       if (Cmd === State_WriteData) begin
            if (RWDataCounter == RWDataNum + 1) begin
                dqs_en <= 1'b0;
            end else if (dclkCounter >= Tdqss & dataIn_rdy === 1) begin
                dqs_en <= 1'b1;
            end else begin
                if (dclkCounter >= Tdqss - 8'h02 & dclk_m === 0) begin
                    dataIn_rdy <= 1'b1;//TODO: writewait 
                end else begin
                    dataIn_rdy <= dataIn_rdy;
                end
                dqs_en <= 1'b0;
                dclkCounter <= dclkCounter + 1'b1;
            end
       end else begin
           dqs_en <= 1'b0;
           dataIn_rdy <= 1'b0;
           dclkCounter <= 8'h00;
       end
   end else begin
       dclkCounter <= 8'h00;
       dataIn_rdy <= 1'b0;
       dqs_en <= 1'b0;
   end 
end

always @(negedge clk_m or negedge rst_n) begin
    if (rst_n) begin
        case (Cmd)
            State_command   : begin
                read_en <=  1'b0;
                dclk_en <= 1'b1;
                CorD    <=  1'b1;
            end
            State_WriteData : begin
                read_en <=  1'b0;
                dclk_en <= 1'b1;
                CorD    <=  1'b0;
            end
            State_ReadData  : begin
                read_en <=  1'b1;
                dclk_en <= 1'b1;
                CorD    <=  1'b1;
            end
            State_adderss   : begin
                read_en <=  1'b0;
                dclk_en <= 1'b1;
                CorD    <=  1'b1;
            end
            State_Idle      : begin
                read_en <=  1'b0;
                dclk_en <= 1'b1;
                CorD    <=  1'b1;
            end
            default: begin
                read_en <=  1'b0;
                dclk_en <= 1'b1;
                CorD    <=  1'b1;
            end
        endcase
    end else begin
        read_en <=  1'b1;
        dclk_en <= 1'b0;
        CorD    <=  1'b1;      
    end
end
reg clkst;
always @(negedge dclk_m or negedge rst_n) begin
    if (rst_n) begin
        case (Cmd)
            State_command : begin
                 ale_r <=    1'b0;
                 cle_r <=    1'b1;
                clk_en <=    1'b1;
                clkst  <=    1'b1;
            end 
            State_WriteData : begin
                if (RWDataNum > 8'h03 & RWDataCounter >= RWDataNum - 8'h02) begin
                    clk_en <=   1'b1;
                    ale_r <=    1'b0;
                    cle_r <=    1'b0;
                end else begin
                    clk_en <=   clkst;
                    clkst <=    1'b0;
                    ale_r <=    1'b1;
                    cle_r <=    1'b1;
                end
            end
            State_ReadData : begin
             clk_en <=    1'b1;
             clkst  <=    1'b1;
                if (RWDataNum > 8'h03 & RWDataCounter >= RWDataNum - 8'h03) begin
                    ale_r <=    1'b0;
                    cle_r <=    1'b0;
                end else begin
                    ale_r <=    1'b1;
                    cle_r <=    1'b1; 
                end
            end
            State_adderss : begin
             clk_en <=    1'b1;
             clkst  <=    1'b1;
                ale_r <=    1'b1;
                cle_r <=    1'b0;
            end
            State_Idle : begin
             clk_en <=    1'b1;
             clkst  <=    1'b1;
                ale_r <=    1'b0;
                cle_r <=    1'b0;
            end
             default: begin
                clkst  <=    clkst;
                clk_en <=    clk_en;
                ale_r <=    ale_r;
                cle_r <=    cle_r;
             end
        endcase
    end else begin
     clk_en <=    clk_en;
        ale_r <= ale_r;
        cle_r <= cle_r; 
        clkst <= 1'b1;
    end
end

always @(posedge clk_m or negedge rst_n) begin
    if (rst_n) begin
        if (dclk == 1'b0 & (Cmd == State_command | Cmd == State_adderss)) begin
            O_DQ_r0 <= InputVal;
        end else begin
            O_DQ_r0 <= O_DQ_r0;
        end
    end else begin
        O_DQ_r0 <= O_DQ_r0;
    end
end

always @(negedge clk_m or negedge rst_n) begin
    if (rst_n) begin
        if (Cmd === State_WriteData) begin
            O_DQ_r1 <= InputVal;
        end else begin
            O_DQ_r1 <= O_DQ_r1;    
        end
    end else begin
        O_DQ_r1 <= O_DQ_r1;    
    end
end


reg ReadStart;
always @(posedge I_DQS or negedge rst_n) begin
    if (rst_n) begin//
        if (Cmd == State_ReadData & I_DQS === 1'b1) begin
            ReadStart <= 1'b1;
        end else begin
            ReadStart <= 1'b0;
        end
    end else begin
       ReadStart <= 1'b0; 
    end
end

always @(posedge clk_m or negedge rst_n) begin
    if (rst_n) begin
        if (Cmd == State_ReadData & RWDataCounter < RWDataNum) begin
            if (ReadStart) begin
                dv_r <= 1'b1;
            end else begin
                dv_r <= 1'b0;
            end
        end else begin
           dv_r <= 1'b0; 
        end
    end else begin
        dv_r <= 1'b0;
    end
end

always @(posedge clk_m or negedge rst_n) begin
    if (rst_n) begin
        if (Cmd === State_ReadData) begin
            if (ReadStart) begin
                val_r <= I_DQ;
                
            end else begin
                val_r <= val_r;
            end
        end else begin
            val_r <= val_r;
        end
    end else begin
        val_r <= val_r;
    end
end

endmodule // Sync_port